package cn.satoken.service.impl;

import cn.dev33.satoken.secure.SaSecureUtil;
import cn.dev33.satoken.stp.SaLoginModel;
import cn.dev33.satoken.stp.StpUtil;
import cn.dev33.satoken.util.SaResult;
import cn.satoken.common.TokenInfo;
import cn.satoken.entity.*;
import cn.satoken.mapper.*;
import cn.satoken.service.SysUserService;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import lombok.RequiredArgsConstructor;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.messaging.simp.SimpMessagingTemplate;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import javax.servlet.http.HttpSession;
import java.util.*;
import java.util.stream.Collectors;

import static cn.satoken.constant.StatusConstant.*;
import static cn.satoken.constant.StatusConstant.USER_LOGIN_ERROR;

/**
 * <h3>saToken</h3>
 * <p></p>
 *
 * @author gdw
 * @since 2025-04-22 09:51:33
 */
@Service
@Transactional
@RequiredArgsConstructor
public class SysUserServiceImpl extends ServiceImpl<SysUserMapper, SysUser> implements SysUserService {
    private final SysUserMapper sysUserMapper;
    private final DeptmentMapper deptmentMapper;
    private final SimpMessagingTemplate messagingTemplate;
    private final SysRoleMapper sysRoleMapper;
    private final SysUserRoleMapper sysUserRoleMapper;
    private final SysMenuMapper sysMenuMapper;
    private final SysRoleMenuMapper sysRoleMenuMapper;
    @Value("${pasword.key}")
    private String paswordKey;

    /**
     * 分页
     * @param page
     * @param size
     * @param map
     * @return
     */
    @Override
    public SaResult selectPage(int page, int size, Map<String, Object> map) {
        Page<SysUser> page1=new Page<>(page,size);
        LambdaQueryWrapper<SysUser> wrapper = new LambdaQueryWrapper<>();
        wrapper.eq(map.get("name")!=null&&!"".equals(map.get("name")), SysUser::getName, map.get("name"))
                .eq(map.get("deptId")!=null&&!"".equals(map.get("deptId")),SysUser::getDeptId, map.get("deptId"))
                .between(map.get("startTime")!=null&&!"".equals(map.get("startTime")),SysUser::getSubmitTime,map.get("startTime"),map.get("endTime"));
        Page<SysUser> sysUserPage = sysUserMapper.selectPage(page1, wrapper);
        sysUserPage.getRecords().forEach(sysUser->{
            LambdaQueryWrapper<SysUserRole> UserRole = new LambdaQueryWrapper<>();
            UserRole.eq(SysUserRole::getUserId,sysUser.getId());
            SysUserRole sysUserRole = sysUserRoleMapper.selectOne(UserRole);
            SysRole sysRole = sysRoleMapper.selectById(sysUserRole.getRoleId());
            sysUser.setRoleName(sysRole.getName());
            sysUser.setStatusName(sysUser.getStatus()==1?"正常":"异常");
            sysUser.setPassword(null);
            System.out.println(StpUtil.isLogin(sysUser.getPhone()));
            sysUser.setBoolLogin(StpUtil.isLogin(sysUser.getPhone()));
            if(sysUser.getDeptId()!=null){
                CrmDeptment crmDeptment = deptmentMapper.selectById(sysUser.getDeptId());
                sysUser.setDeptName(crmDeptment.getName());
            }
        });
        return SaResult.data(sysUserPage);
    }

    /**
     * 根据部门id查询
     * @param deptId
     * @return
     */
    @Override
    public SaResult findByDeptId(Long deptId) {
        LambdaQueryWrapper<SysUser> wrapper = new LambdaQueryWrapper<>();
        wrapper.eq(SysUser::getDeptId, deptId).eq(SysUser::getStatus,USER_SUCCESS_STATUS);
        List<SysUser> sysUsers = sysUserMapper.selectList(wrapper);
        sysUsers.forEach(sysUser->{
            sysUser.setPassword(null);
        });
        return SaResult.data(sysUsers);
    }

    /**
     * 登录
     *
     * @param user
     * @param session
     * @return
     */
    @Override
    public SaResult login(SysUser user, HttpSession session) {
        LambdaQueryWrapper<SysUser> wrapper = new LambdaQueryWrapper<SysUser>();
        wrapper.eq(SysUser::getPhone, user.getPhone());
        SysUser sysUser = sysUserMapper.selectOne(wrapper);
        String text2 = SaSecureUtil.aesDecrypt(paswordKey, sysUser.getPassword());
        if(text2.equals(user.getPassword())){
            if (sysUser.getStatus()==USER_FAIL_STATUS){
                return SaResult.error(USER_LOGIN_ABNORMAL);
            }
            StpUtil.login(sysUser.getPhone(),new SaLoginModel()
                    .setDevice("PC")
                    .setIsLastingCookie(false)
                    .setTimeout(60 * 60 * 24 * 1) //一天就行
                    .setIsWriteHeader(false)
            );
            TokenInfo tokenInfo =new TokenInfo(StpUtil.getTokenInfo()) ;
            getTokenInfo(tokenInfo,sysUser);
            System.out.println(tokenInfo.getMenus());
            //登录成功后，发送通知
            messagingTemplate.convertAndSend("/topic/login",sysUser.getName()+"：登陆系统");
            // 清除验证码，避免重用
            session.removeAttribute("captcha");
            return SaResult.data(tokenInfo);
        }else {
            return SaResult.error(USER_LOGIN_ERROR);
        }
    }
    public void getTokenInfo(TokenInfo tokenInfo ,SysUser sysUser){
        tokenInfo.setTag(sysUser.getName());
        tokenInfo.setUserId(sysUser.getId());
        //查询角色
        LambdaQueryWrapper<SysUserRole> userrolewrapper = new LambdaQueryWrapper<>();
        userrolewrapper.eq(SysUserRole::getUserId, sysUser.getId());
        List<SysUserRole> sysUserRoles = sysUserRoleMapper.selectList(userrolewrapper);
        if(sysUserRoles!=null&&sysUserRoles.size()>0){
            List<Long> roleIdList = sysUserRoles.stream()
                    .map(SysUserRole::getRoleId)
                    .collect(Collectors.toList());
            List<SysRole> sysRoles = sysRoleMapper.selectBatchIds(roleIdList);
            List<String> array = sysRoles.stream().map(SysRole::getName)
                    .collect(Collectors.toList());
            tokenInfo.setRoles(array);
            //查找权限
            LambdaQueryWrapper<SysRoleMenu> rolemenuwrapper = new LambdaQueryWrapper<>();
            rolemenuwrapper.in(SysRoleMenu::getRoleId, roleIdList);
            List<SysRoleMenu> sysRoleMenus = sysRoleMenuMapper.selectList(rolemenuwrapper);
            List<Long> collect = sysRoleMenus.stream().map(SysRoleMenu::getMenuId).collect(Collectors.toList());
            List<SysMenu> sysMenus = sysMenuMapper.selectBatchIds(collect);
            tokenInfo.setMenus(buildRouterTree(sysMenus));
        }
    }
    public List<TokenInfo.Router> buildRouterTree(List<SysMenu> menus) {
        // 使用更高效的初始化容量，假设平均每个父节点有5个子菜单
        Map<Long, List<SysMenu>> parentMap = new HashMap<>(menus.size() / 5);

        // 优化分组操作，避免使用stream的额外开销
        for (SysMenu menu : menus) {
            parentMap.computeIfAbsent(menu.getParentId(), k -> new ArrayList<>()).add(menu);
        }

        // 构造树结构，从 parentId 为 0 的开始
        return buildRouters(parentMap, 0L);
    }

    private List<TokenInfo.Router> buildRouters(Map<Long, List<SysMenu>> parentMap, Long parentId) {
        List<SysMenu> childrenMenus = parentMap.get(parentId);
        if (childrenMenus == null || childrenMenus.isEmpty()) {
            return Collections.emptyList(); // 使用不可变空列表减少内存分配
        }

        List<TokenInfo.Router> routers = new ArrayList<>(childrenMenus.size());

        for (SysMenu menu : childrenMenus) {
            TokenInfo.Router router = new TokenInfo.Router();
            router.setId(menu.getId().toString());
            router.setTitle(menu.getTitle());

            if (menu.getParentId().equals(0L) && menu.getMenuName() != null) {
                router.setPath(menu.getPath());
                router.setName(menu.getMenuName());
                router.setIcon(menu.getIcon());
            }
            // 处理子菜单
            List<SysMenu> leafMenus = parentMap.get(menu.getId());
            if (leafMenus != null && !leafMenus.isEmpty()) {
                List<TokenInfo.Menu> childMenus = new ArrayList<>(leafMenus.size());
                for (SysMenu sub : leafMenus) {
                    childMenus.add(new TokenInfo.Menu(
                            sub.getPath(),
                            sub.getMenuName(),
                            sub.getTitle(),
                            sub.getIcon()
                    ));
                }
                router.setChildren(childMenus);
            } else {
                router.setChildren(Collections.emptyList()); // 避免null
            }

            routers.add(router);
        }
        return routers;
    }
}
